home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / X11 / tclMotif-1.4 / doc / paper.txt < prev    next >
Encoding:
Text File  |  1995-06-29  |  21.1 KB  |  410 lines

  1. A Tcl Binding to Motif
  2.  
  3. Jan Newmarch
  4. University of Canberra
  5.  
  6. Introduction
  7.  
  8. The X Window System is now accepted as the standard windowing systems for
  9. Unix graphics workstations and terminals. It provides a low-level set of
  10. tools to build applications. Most applications now are built using a
  11. higher-level toolkit which typically supplies objects usually known as
  12. widgets. There are a number of such toolkits, but the one that has achieved
  13. the major success is the Motif toolkit based on the Xt Intrinsics. Motif
  14. has defined a look-and-feel that is copied to a greater or lesser extent by
  15. other toolkits, and forms a component of specifications such as COSE.
  16.  
  17. The specification for Motif basically assumes a C-like language, and the
  18. only implementation of that specification is the C library from OSF. This
  19. has led to many bindings to this library from alternative systems. These
  20. include even higher-level systems that can be ported across different
  21. window systems, to specific language bindings. These include C++, Ada,
  22. Prolog, Lisp, Poplog and the Korn Shell.
  23.  
  24. Tcl (Tool Command Language) is a type-free interpreted language that was
  25. designed to be embedded into applications requiring a command language for
  26. communication with users, to parse specification files requiring
  27. language complexity, and to provide a macro language for applications such
  28. as spreadsheets. The intent was to do it right once, so that
  29. application-writers need not invent their own language and write their own
  30. parsers and semantic evaluators.
  31.  
  32. Tcl has been extended with an X Window toolkit not based on the Intrinsics,
  33. that supplies a set of widgets directly accessible from tcl. This Tk
  34. toolkit is generally run from a program called ``wish'' that sets up a
  35. suitable environment and then calls an event processing loop for the Tk
  36. widgets.
  37.  
  38. However, there are differences between Tk and Motif, some minor and some
  39. major. These differences are no better nor worse than the differences
  40. between other toolkits such as InterViews, but do seem to give
  41. rise to some heated debate at times. For example, there is the claim that
  42. Motif must be slower than Tk because of the complexity of implementation
  43. above Xt. On the other hand, it must be faster because Tcl/Tk is
  44. interpreted. Tcl/Tk programs are often pointed at as significantly shorter
  45. than equivalent Motif programs, without determining whether this difference
  46. is caused by choice of language - C versus Tcl, or choice of toolkit -
  47. Motif versus Tk. Other issues such as the complexity of Motif XmStrings
  48. against their value for internationalisation are often discussed.
  49.  
  50. This paper reports on a project that attempts to remove some of the
  51. variables from this debate. It provides a binding of Tcl to Motif so that
  52. Tcl programs can be written directly using the Motif C libraries. This
  53. binding is by a library of C functions called Tm (Tcl Motif). The focus
  54. in this paper is on the mechanisms of this implementation, but some
  55. discussion is given to the language against toolkit debate.
  56.  
  57. Recently the author became aware of the Wafe system, which was a binding
  58. of the Athena widgets to tcl. This project had different aims to this
  59. one, but there are many common elements. This is also discussed.
  60.  
  61. Elements of tcl
  62.  
  63. Elements of Motif
  64.  
  65. Elements of Tk
  66.  
  67. The moat Interpreter
  68.  
  69. Tm borrows heavily from Tk in many places. Tk has an interpreter called
  70. ``wish'' (Window Shell) that sets up the Tk world, sources a Tcl/Tk file
  71. and then enters a Tk event processing loop. This is sufficiently general
  72. that many useful Tk programs can be written just using ``wish'' as
  73. application environment. Problems requiring a richer environment may use a
  74. modified ``wish''.
  75.  
  76. Tm uses this idea and supplies an interpreter called ``moat'' (MOtif And Tcl)
  77. This sets up an Xt world by calling XtAppInitialize, creates a
  78. Tcl interpreter, sources a Tcl file, realizes all widgets and then enters
  79. the Xt event loop.
  80.  
  81. Creating Widgets
  82.  
  83. Widgets are created using Tcl commands registered with the Tcl interpreter
  84. on initialisation.  These creation commands follow the design of the Tk
  85. system, in that there is one creation command per class of widget. In
  86. addition, Motif has a set of dialogs, which are convenience routines for
  87. creating a compound widget in a way that is supposed to be invisible to the
  88. C programmer and act as though they create single objects. These routines
  89. are also implemented as widget creation functions in Tm. It is not hard to
  90. ``special case'' some functions within Tm to handle these dialogs.
  91. Motif also ``special cases'' two common operations - creating a ScrolledList
  92. and a ScrolledText widget. This is also handled by Tm. In both of these
  93. special cases, the parent is brought into the Tm system, and is given a
  94. unique name. This name is produced from the pathname by introducing an
  95. extra dot into the path.
  96.  
  97. Widget Commands
  98.  
  99. When a widget is created two major things occur: an Xt/Motif widget is
  100. created and a command with the widget name is added to the Tcl interpreter.
  101. This gives an object-oriented flavour to the system in that a widget becomes
  102. a command which is interpreted as an object with methods.
  103.  
  104.  
  105. Widget Methods
  106.  
  107. Each widget has a set of methods applicable to it. In general, most widgets
  108. inherit from TmCore. This allows Xt methods such as ManageChild and
  109. UnmanageChild to be handled from one function.  The design of Tcl registers
  110. a command handler per command; widgets that have no special methods simply
  111. register the TmCore handler. Widgets with more methods register a different
  112. handler which may call TmCore eventually in an inheritance chain.
  113.  
  114. Each widget in fact has special methods: the callback procedures for that
  115. class. This is handled by TmCore rather than in individual command handlers
  116. because of regularities in the implementation of Motif that are better
  117. discussed in the next section. Briefly, each callback can be recognised because
  118. it ends in the string ``Callback''. This can then be added to the Xt widget
  119. callbacks using XtAddCallback in the TmCore handler, without worrying about
  120. exactly which callback it is.
  121.  
  122. In C, when a callback is added to a widget a specific C function is
  123. specified that will be invoked when the action for that callback occurs.
  124. However, we want a Tcl function to be executed. This is easily done by
  125. using a generic C callback function that handles every widget, almost
  126. without exception. When a callback is added in Xt, the ClientData field is
  127. set to point to a structure containing the Tcl interpreter and the string
  128. that is the Tcl callback function. This gives the generic C callback
  129. fucntion enough information to execute the Tcl function.
  130.  
  131. Resource Converters
  132.  
  133. The presence of resource converters within Xt is the key to the ease with
  134. which this binding has been implemented. Previous sections have used
  135. existing Tcl/Tk concepts (and code) to a large extent. It is now time for
  136. Xt to play a significant part. Xt allows users to store resource values in
  137. files such as .Xdefaults to control run-time values for the program. This
  138. user-level control is one of the major features of Xt. The resource files
  139. contain strings representing the values the user wants. For example, a
  140. width may be set to the string "200". Xt, and all toolkits built above it,
  141. supply ``resource converters'' to transform these string values into the
  142. internal data types required by the program.
  143.  
  144. To perform such conversions, Xt supplies a number of useful functions.
  145. XtGetResourceList and XtGetConstraintList return lists of resources
  146. applicable to each class of widget. Elements in these lists are structures
  147. that contain strings representing the source and destination types, and
  148. the size (in bytes) of the destination type. The string representations
  149. allow searches for source types, and the structure when located in the list
  150. provides enough information to call XtConvertAndStore. This looks up a list
  151. of registered converters and calls the converter function if found.
  152.  
  153. This makes one side of this binding trivially simple: if a resource can be
  154. specified in a resource file then a converter exists from string to
  155. internal value. The Tcl setValues function simply has to locate the
  156. resource in these resource lists and call XtConvertAndStore. It can then use 
  157. XtSetValues to install the converted value, and Xt and Motif do the rest!
  158.  
  159. This also makes the naming conventions in tcl very easy. Because resources
  160. are specified as strings, the names can be used by tcl without change.
  161. Motif is quite consistent in its use of these names (alphabetic only,
  162. beginning with a lower case letter, and with other words in the name
  163. capitalised). Tk uses this convention as well, so the similarity in
  164. programs across the two systems is maintained.
  165.  
  166. Well, it isn't really trivial. Some resources require widget values, such
  167. as edge bindings in Form. Tm needs to supply another converter, from
  168. TmWidgetName to Xt Widget. This, and similar needs are answered by just
  169. adding more converters. A more serious problem is addressed in the next
  170. section.
  171.  
  172. The largest amount of work in this binding is in implementing getValues.
  173. This requires conversion from internal type to strings. For many types
  174. such as Dimension there is no support from either Xt or Motif. However,
  175. for enumerated types such as arrowDirection for the ArrowButton widget,
  176. Motif not only gives ``Representation Type'' converters for conversion
  177. from String to enumerated type, but also allows converters in the reverse
  178. direction to be installed, so that names such as ``arrow_left' can be
  179. generated. This was intended for GUI building systems which need to use
  180. symbolic names when setting or getting widget values, but it suits tcl
  181. very well, thank you.
  182.  
  183. Secondary Resources
  184.  
  185. Xt allows objects to have subobjects. There are not many examples of these.
  186. Editors with Output subobjects and Input subobjects are the principal
  187. ones. The nasty part is that these subobjects can have their own
  188. resources and Xt supplies no means for an application to access them.
  189. Xt has a ``hook'' to allow the toolkit library to access them, but not the
  190. application (in Motif at any rate they are static to a file, so there is no
  191. direct way of accesing them). Fortunately, Motif (not Xt) supplies
  192. the function XmGetSecondaryResources to get these.
  193.  
  194. Special Cases
  195.  
  196. Convenience functions
  197.  
  198. {Scrolled List, Dialogs}
  199. Motif supplies convenience functions of several types. Some such as the
  200. various RowColumn functions of XmCreateMenuBar, XmCreateOptionMenu, etc
  201. just set extra parameters for RowColumn and are easy to handle. Two other
  202. sets are the ScrolledObject functions such as XmCreateScrolledList and
  203. XmCreateScrolledText and the Dialog convenience functions such as
  204. XmCreateFormDialog etc. Both of these sets of functions create a pair
  205. of widgets, not just a single one. For example, XmCreateScrolledList
  206. creates a ScrolledWindow parent and the List child, whereas the Dialog
  207. functions create a Popup shell parent. In all cases, the Create function
  208. returns the child widget.
  209.  
  210. The intent in Motif was to hide the parent widgets. Unfortunately it canot be
  211. done completely for several reasons. Firstly, when the ScrolledList (or any
  212. of the others) is destroyed, it is the parent that must be destroyed, not
  213. just the child. Otherwise a memory leak occurs. Secondly, when you need to
  214. set constraint resources (such as placing the ScrolledList into a Form), it
  215. is the parent widget that needs resources set, not the child. Thus a
  216. mechanism to access the parent is required.
  217.  
  218. In Motif, this may be done by the call XtParent, which returns the Xt
  219. widget parent. In this binding it is neccessary to return a tcl widget
  220. parent, and this may be a problem. The tcl parent must be generated
  221. automatically, but must be guaranteed unique. Otherwise there may be an
  222. accidental name collision with other tcl widgets. The Motif naming
  223. mechanism (tacking ``SW'' onto Scrolled Objects, ``_popup'' onto dialogs)
  224. does not guarantee this. Fortunately, the particular naming syntax used in
  225. this binding (based on Tk), where widget names are separated by dots ``.''
  226. does allow this, by inserting an extra dot. For example,
  227.  
  228. scrolledList .l
  229. puts stdout [.l parent]
  230.  
  231. produces the unique `..l''.
  232.  
  233. Timing conversions
  234.  
  235. Some resources can only be set at creation time. Such resources are of two
  236. types: the first is exemplified by ... in which the value of this resource
  237. is used during the Initialize function and is thereafter unused. The second
  238. is one that cannot be changed because it has too many ramifications. Such
  239. a resource is the ScrollingPolicy of the ScrolledWindow widget. These
  240. resources must be converted from their String value to be used in the Args
  241. array to the XmCreate... function.
  242.  
  243. On the other hand, some resources use widget values in their calculation.
  244. For example, any Dimension or Position resource such as the width uses the
  245. Motif UnitType resource in its calculation, in order to gain independance
  246. of the display size characteristics. Similarly, the LabelPixmap resource of
  247. Labels needs to have a foreground and background before it can be created.
  248.  
  249. These differing cases cause a problem. The convertor functions from String
  250. to Value use a widget parameter, and in the first case this can only be the
  251. parent (as the child Create function cannot have been called yet) whereas
  252. in the second it requires the widget itself. The special case code to
  253. handle this is not only a maintainance problem, but is not guaranteed to be
  254. correct in the first place as neither Motif nor Xt offer any support to
  255. distinguish the cases (the recently released WKSH also faced this problem
  256. and missed the LabelPixmap case, probably because it is quite well hidden
  257. in the Motif source).
  258.  
  259. This binding divides the resources into ones which must be converted before
  260. creation, those that must be converted after creation, and those for which
  261. it does not matter. These are all handled correctly. A case which is not
  262. handled is where the conversion must be done during creation.
  263. Fortunately this does not occur, as it would break any bindings such as
  264. this one that rely on the resource converter mechanism.
  265.  
  266. XmStringTables
  267.  
  268. Various widgets such as ScrolledList use XmStringTables, which are arrays
  269. of XmStrings. Motif is inconsistent in its internal use of these arrays -
  270. sometimes they are NULL-terminated, most times they are not. This means
  271. that there is no way of determining from the XmStringtable itself exactly
  272. how many elements it contains. This must be found from other means. For
  273. example, the size of the List resource ``items'' is found in the List
  274. resource ``itemCount'', and the size of the ``selectedItems'' resource is
  275. found in the `selectedItemsCount'' resource. When an XmStringTable is
  276. converted into a String, this size must be known to the resource converter.
  277. This could be determined from the widget type and resource name (eg for
  278. ``items'' of a List widget, determine it from ``itemCount''), but the
  279. resource name is not available to the resource converter. Thus special case
  280. code must be inserted before any  resource converter can be called, just in
  281. case it is one of these cases. This is inelegant and an overhead in time
  282. for all of the resource conversions, whatever type.
  283.  
  284. Text Verify Callbacks
  285.  
  286. Motif callbacks provide extra information through the callback data. This
  287. is generally a pointer to a structure specific to the widget type. Fro
  288. example, the PushButton callback structure contains a field ``click_count''
  289. to allow distinction between single and multiple clicks. Generally these
  290. structures contain ``read only'' information that is not to be modified.
  291.  
  292. The Text widget has a set of ``verify'' callbacks that point to read/write 
  293. structures. The purpose of these is to allow for things such as password
  294. entry, where the application needs to be given the characters typed in, but
  295. must be able to signal to Text not to echo these characters. This is done
  296. by setting the ``doit'' field in the XmTextVerifyCallbackStruct to False.
  297. These calllbacks are actually called by Motif in an unusual way: for
  298. example, when characters are typed in Motif decodes the characters, calls
  299. the modifyVerifyCallbacks, examines the return state of the callback
  300. structure and only then actually inserts (or not) the characters typed.
  301.  
  302. This is handled by creating a global variable and passing its name (rather
  303. than its value) into the callback. The application can then modify its
  304. value, and this is used to set the Motif fields as appropriate. The Motif
  305. mechanism is odd in this respect, and the tcl binding shows this in
  306. practice.
  307.  
  308. Inconsistencies and Bugs
  309.  
  310. By and large tcl and Motif work well together. One area that does not integrate
  311. perfectly concerns lists. In Motif there are sometimes lists of XmStrings, and
  312. when they are represented as strings individual elements are separated by
  313. commas.  tcl on the other hand represents lists as elements separated by
  314. whitespace.  Both handle lists containing whitespace in different ways, with
  315. the tcl solution being more general. Motif would have (say for a list of
  316. authors of Motif books)
  317.  
  318. Dan Heller, Jan Newmarch, Thomas Berlage
  319.  
  320. tcl would have
  321.  
  322. {Dan Heller} {Jan Newmarch} {Thomas Berlage}
  323.  
  324.  
  325. Hiding Complexity
  326.  
  327. One of the hurdles in any Xt program is the complexity of concepts in even
  328. a trivial program. The Tk library hides parts of this by placing initialisation
  329. and the event loop handler into the ``wish'' intepreter, and by making the
  330. callback mechanism simpler. The Tm library copies most of this, and so achieves
  331. the same simplicity in this respect.
  332.  
  333. Motif adds further layers of complexity above this. A particularly tricky 
  334. hurdle to overcome is the support for internationalisation offered by
  335. XmStrings. The Tm library handles XmStrings internally, and uses the normal
  336. tcl String mechanism for all purposes. Thus this mechanism is hidden from
  337. the tcl programmer. It is still present in Motif, so a Label widget can
  338. display Japanese text as specified in a resource file. The ability of tcl to
  339. manage this is still in doubt (it is at least 8-bit clean, and Tk can use the
  340. X11 support to display ISO 8859-1 characters).
  341.  
  342. Validation
  343.  
  344. The Tm library is built on Motif. Can it be certified as Motif compliant?
  345. Well, actually, no. This is basically a library into Motif, and as such
  346. must be compliant with the AES (Application Environment Specification).
  347. The AES details what functions a Motif library must make available, and this
  348. binding falls short of that. For example, Tm hides XmStrings and has no
  349. explicit support for them. So it fails the test of ``coverage'' as you can't
  350. do everything in Tm that you can using the OSF C library.
  351.  
  352. On the other hand, applications built using this library can be certified
  353. as Motif compliant. Application compliance just means that *out of the
  354. elements of GUI used*, these conform to the Motif Style Guide. You can
  355. really muck up a Tm application by putting the menu bar at the bottom, with
  356. the Help button on the left and even worse things, and these will fail to 
  357. give you Motif compliance, but if you aren't that silly you will be able
  358. to get Motif certification for applications built using Tm.
  359.  
  360.  
  361. Wafe and WKSH
  362.  
  363. The WKSH is a binding of the Korn Shell to Motif. It deals with the same
  364. problems as this binding, in that it has to convert Strings to Motif types.
  365. It appears to use the same mechanisms, and has run into the same problems.
  366. For example, it handles the Conversion versus Creation problem for
  367. resources such as width by disallowing setting of such
  368. resources during creation! In this binding it is deferred until it is
  369. valid. The lack of support by Xt and Motif in this area is evidenced by the
  370. failure of the WKSH to correctly handle the LabelPixmap resource in its
  371. initial release.
  372.  
  373. WKSH models itself on the syntax of the Motif C language binding. The
  374. function calls use the same names, such as XmCreateMainWindow. The binding
  375. also partly preserves the positional syntax of the C language, so that a C call
  376.  
  377. w = XmCreateLabel(parent, name, args, argc)
  378.  
  379. becomes
  380.  
  381. XmCreateLabel parent w name args...
  382.  
  383. The WKSH binding actually adds an extra argument to replace the return value of
  384. the function, and uses the varargs style of argument passing that has
  385. become quite popular within the X world.
  386.  
  387. The WKSH binding follows this even further in defining functions such as
  388. XtManageChildren which place the action followed by arguments.
  389.  
  390. The Wafe binding follows this same principle of action followed by object,
  391. but without the positional argument complexity of WKSH. This particular
  392. binding seems to have suffered confused press in that it produces a Tcl
  393. binding to Xt on one side, and an open-ended binding of Tcl/Xt to
  394. almost any language on the other. This generality seems to have led to
  395. impressions such as "it is a way of writing Perl programs that use Tcl to
  396. talk to Xt". The current status of Wafe is that it binds Tcl to a variety
  397. of Xt-based widget libraries, with Athena being well supported, and Motif
  398. in beta. The Wafe callback model is very different to Tm. In Tm, the Motif
  399. style is followed in that the callback contains useful information and
  400. helps to give the ``feel'' part of the ``look and feel'' paradigm. Wafe
  401. uses a limited set of callbacks to produce popup dialogs.
  402.  
  403. In implementation, the Wafe and Tm systems follow very similar lines as
  404. there is really only one way of doing much of the binding of Xt toolkits to
  405. string languages such as Tcl and Ksh. The authors of Wafe suffer the problem
  406. of only having access to Motif
  407. 1.1 at the time of writing, so the additional aids supplied in Motif 1.2
  408. are not available to them. This is a distinct drawback. I am in active email
  409. correspodence with them, to avoid duplicating work.
  410.